using FileManager.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;

namespace FileManager.Services
{
    public class FileExportService
    {
        private readonly DatFileDecryptor _datFileDecryptor;

        public FileExportService(DatFileDecryptor datFileDecryptor)
        {
            _datFileDecryptor = datFileDecryptor;
        }

        /// <summary>
        /// 批量导出文件到指定目录
        /// </summary>
        /// <param name="files">要导出的文件列表</param>
        /// <param name="targetDirectory">目标目录</param>
        /// <param name="decryptDatFiles">是否解密.dat文件</param>
        /// <param name="preserveDirectoryStructure">是否保留目录结构</param>
        /// <param name="progressCallback">进度回调</param>
        /// <returns>导出成功的文件数量</returns>
        public async Task<int> ExportFilesAsync(
            List<FileItem> files,
            string targetDirectory,
            bool decryptDatFiles = true,
            bool preserveDirectoryStructure = false,
            Action<int, int, string> progressCallback = null)
        {
            // 参数验证
            if (files == null || files.Count == 0)
            {
                MessageBox.Show("没有要导出的文件", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                return 0;
            }

            if (string.IsNullOrEmpty(targetDirectory))
            {
                MessageBox.Show("请指定导出目录", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return 0;
            }

            // 创建目标目录
            if (!Directory.Exists(targetDirectory))
            {
                try
                {
                    Directory.CreateDirectory(targetDirectory);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"创建导出目录失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return 0;
                }
            }

            int successCount = 0;
            int failedCount = 0;
            int totalCount = files.Count;
            List<string> failedFiles = new List<string>();

            for (int i = 0; i < files.Count; i++)
            {
                var file = files[i];
                string fileName = file.FileName;
                string targetPath;

                // 检查源文件是否存在
                if (!File.Exists(file.FilePath))
                {
                    failedCount++;
                    failedFiles.Add($"{fileName} (文件不存在)");
                    progressCallback?.Invoke(i + 1, totalCount, $"{fileName} (文件不存在)");
                    continue;
                }

                try
                {
                    if (preserveDirectoryStructure)
                    {
                        // 保留原始目录结构
                        string relativePath = GetRelativePath(file.FilePath);
                        string targetSubDir = Path.Combine(targetDirectory, relativePath);

                        if (!Directory.Exists(targetSubDir))
                        {
                            Directory.CreateDirectory(targetSubDir);
                        }

                        targetPath = Path.Combine(targetSubDir, fileName);
                        // 处理文件名冲突
                        targetPath = GetUniqueFilePath(targetPath);
                    }
                    else
                    {
                        // 所有文件放在同一目录下
                        targetPath = Path.Combine(targetDirectory, fileName);

                        // 处理文件名冲突
                        targetPath = GetUniqueFilePath(targetPath);
                    }

                    // 导出文件
                    if (file.IsEncrypted && decryptDatFiles)
                    {
                        // 解密.dat文件并保存
                        try
                        {
                            string extension = _datFileDecryptor.DetectImageFormat(await _datFileDecryptor.DecryptDatFileAsync(file.FilePath));
                            targetPath = Path.ChangeExtension(targetPath, extension);
                            await _datFileDecryptor.DecryptAndSaveAsImageAsync(file.FilePath, targetPath);
                            successCount++;
                        }
                        catch (Exception ex)
                        {
                            failedCount++;
                            failedFiles.Add($"{fileName} (解密失败: {ex.Message})");
                            Console.WriteLine($"导出文件 {file.FilePath} 失败: {ex.Message}");
                            continue;
                        }
                    }
                    else
                    {
                        // 直接复制文件
                        try
                        {
                            File.Copy(file.FilePath, targetPath, true);
                            successCount++;
                        }
                        catch (Exception ex)
                        {
                            failedCount++;
                            failedFiles.Add($"{fileName} (复制失败: {ex.Message})");
                            Console.WriteLine($"导出文件 {file.FilePath} 失败: {ex.Message}");
                            continue;
                        }
                    }
                }
                catch (Exception ex)
                {
                    failedCount++;
                    failedFiles.Add($"{fileName} (处理失败: {ex.Message})");
                    Console.WriteLine($"处理文件 {file.FilePath} 时发生错误: {ex.Message}");
                }

                // 报告进度
                progressCallback?.Invoke(i + 1, totalCount, file.FileName);
            }

            // 显示导出结果摘要
            if (failedCount > 0)
            {
                string message = $"导出完成！\n成功导出 {successCount} 个文件\n失败 {failedCount} 个文件";
                if (failedFiles.Count > 0 && failedFiles.Count <= 10)
                {
                    message += "\n\n失败的文件:\n" + string.Join("\n", failedFiles);
                }
                else if (failedFiles.Count > 10)
                {
                    message += $"\n\n前10个失败的文件:\n" + string.Join("\n", failedFiles.GetRange(0, Math.Min(10, failedFiles.Count))) + $"\n... 还有 {failedFiles.Count - 10} 个失败文件";
                }
                MessageBox.Show(message, "导出结果", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else if (successCount > 0)
            {
                MessageBox.Show($"成功导出 {successCount} 个文件", "导出完成", MessageBoxButton.OK, MessageBoxImage.Information);
            }

            return successCount;
        }

        /// <summary>
        /// 获取相对路径（去掉驱动器部分）
        /// </summary>
        /// <summary>
        /// 获取相对路径（相对于原始扫描目录）
        /// </summary>
        /// <param name="fullPath">完整文件路径</param>
        /// <returns>相对路径</returns>
        private string GetRelativePath(string fullPath)
        {
            try
            {
                string directory = Path.GetDirectoryName(fullPath);
                if (string.IsNullOrEmpty(directory))
                    return string.Empty;

                // 去掉驱动器部分，如 "C:\"
                if (directory.Length > 2 && directory[1] == ':' && directory[2] == '\\')
                {
                    return directory.Substring(3);
                }

                return directory;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取相对路径失败: {ex.Message}");
                return string.Empty;
            }
        }

        /// <summary>
        /// 获取唯一的文件路径，避免覆盖现有文件
        /// </summary>
        private string GetUniqueFilePath(string filePath)
        {
            if (!File.Exists(filePath))
                return filePath;

            string directory = Path.GetDirectoryName(filePath);
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
            string extension = Path.GetExtension(filePath);
            int counter = 1;

            string newFilePath;
            do
            {
                newFilePath = Path.Combine(directory, $"{fileNameWithoutExtension}_{counter}{extension}");
                counter++;
            } while (File.Exists(newFilePath));

            return newFilePath;
        }
    }
}